let ErrorUtils = require('../utils/error/ErrorUtils');
let {User, WechatUser} = require('../models');
const Joi = require('joi');
const lodash = require('lodash');
const crypto = require('crypto');
const config = require('../config');
const {infoLogger, errorLogger} = require('../config').logger;
let redis = require('../redis');
let WXBizDataCrypt = require('../utils/wechat/WXBizDataCrypt');

class UserService {

    static checkUserData(data) {
        let schema = Joi.object({
            username: Joi.string().min(3).max(16).required(),
            password: Joi.string().min(3).max(16).required(),
        });
        let result = Joi.validate(data, schema);
        return result;
    }

    /**
     * 获取用户信息
     * @returns {Promise<void>}
     */
    static async index(id) {
        if (!id) {
            ErrorUtils.throwApiError(ErrorUtils.ID_INVALID);
        }
        return await User.findById(id);
    }

    /**
     * 获取用户列表
     * @returns {Promise<void>}
     */
    static async list() {
        return await User.find();
    }

    /**
     * 创建用户
     * @param ctx
     * @returns {Promise<void>}
     */
    static async create(data) {
        await this.checkUserData(data);
        let userinfo = await User.findOne()
            .where("username", data.username)
            .lean()
            .exec();
        if (userinfo) {
            ErrorUtils.throwApiError(ErrorUtils.USER_HAS_EXIST);
        }
        return await User.create(data);
    }

    static async create(data) {
        infoLogger.info('>>>>>>创建用户,请求参数为:', data);
        await UserService.checkUserData(data);
        let result = await User.findOne().where("username", data.username);
        if (!result) {
            let password = data.password;
            password = password + config.auth.salt;
            password.toLowerCase();
            // 创建一个hash对象
            const md5 = crypto.createHash('md5');
            // 往hash对象中添加摘要内容
            md5.update(password);
            password = md5.digest('hex');
            result = await User.create({
                username: data.username,
                password: password,
            })
        }
        return result;
    }

    /**
     * 修改用户
     * @param ctx
     * @returns {Promise<void>}
     */
    static checkUpdateUserData(data) {
        let schema = Joi.object({
            id: Joi.string().min(10).max(30).required(),
            username: Joi.string().min(3).max(15).required(),
            password: Joi.string().min(6).max(16).required(),
            phone: Joi.string().min(11).max(11).required()
        });
        let result = Joi.validate(data, schema);
        return result;
    }

    static async update(data) {
        if (!data.id) {
            ErrorUtils.throwApiError(ErrorUtils.ID_INVALID);
        }
        let id = data.id;
        data = lodash.omit(data, ['id']);
        return await User.update({_id: id}, data);
    }

    /**
     * 删除用户
     * @param id
     * @returns {Promise<void>}
     */
    static async delete(id) {
        if (!id) {
            ErrorUtils.throwApiError(ErrorUtils.ID_INVALID);
        }
        return await User.remove({_id: id});
    }

    static async saveUserInfo(data) {
        let isNew = false;
        let userDoc;
        if (lodash)
            if (!lodash.isEmpty(data.openid)) {
                userDoc = await WechatUser.findOne({openId: data.openid}).exec();
            }
        if (!userDoc) {
            isNew = true;
            // 创建用户
            let obj = {
                openId: data.openid,
                sessionKey: data.session_key
            };
            if (!lodash.isEmpty(data.unionid)) {
                obj.unionId = data.unionid;
            }
            userDoc = await WechatUser.create(obj);
        } else {
            if (!lodash.isEmpty(userDoc.nickName)) {
                isNew = true;
            }
        }
        if (isNew) {
            //新用户的后端逻辑处理
        }
        return {
            isNew, userDoc
        };
    }

    static createValidate(data) {
        let schema = Joi.object({
            iv: Joi.string().required(),
            encryptedData: Joi.string().required(),
        });
        let result = Joi.validate(data, schema);
        return result;
    }

    /**
     * 解密用户数据
     * @returns {Promise<void>}
     */
    static async wechatDecryptUserData(currentUser, body) {
        infoLogger.info(">>>>>>解密用户信息接口口开始,请求参数", body);
        infoLogger.info(">>>>>>当前用户信息:", currentUser);
        //校验数据
        await UserService.createValidate(body);
        //获取用户的openid
        let openId = currentUser.openId;
        //获取sessionKey
        let sessionKey = await redis.hmget(`${config.auth.wechatLoginPrefix}${openId}`, 'sessionKey');
        infoLogger.info(">>>>>:sessionKey数组:", sessionKey);
        if (!sessionKey || sessionKey.length == 0 || !sessionKey[0]) {
            ErrorUtils.throwApiError(ErrorUtils.USER_HAS_EXIST);
        }
        //return;
        // decrypt user data
        let decryptData = await UserService.decryptUserData(sessionKey[0], body.encryptedData, body.iv);
        // 将数据存储在用户平台
        let userLocal = await UserService.updateUserInfo(currentUser._id, decryptData);
        // update current user
        currentUser = userLocal.toJSON();
        // set redis
        let response = lodash.pick(userLocal.toJSON(), [
            '_id', 'avatarUrl', 'gender', 'nickName', 'city', 'province', 'openId', 'unionId'
        ]);
        //console.log(response);
        await redis.hmset(`${config.auth.wechatLoginPrefix}${openId}`, response);
        await redis.expire(`${config.auth.wechatLoginPrefix}${openId}`, config.auth.wechatTtl);

        return currentUser;
    }

    /**
     * 解密用户信息
     * @param sessionKey
     */
    static decryptUserData(sessionKey, encryptedData, iv) {
        let decrypt = new WXBizDataCrypt(config.wechat.appId, sessionKey);
        return decrypt.decryptData(encryptedData, iv);
    }

    /**
     * 修改用户信息
     * @param userData
     */
    static updateUserInfo(userId, userData) {
        if (!userData) {
            ErrorUtils.throwApiError(ErrorUtils.DECODE_INFO_NOT_EXIST);
        }
        return WechatUser.findByIdAndUpdate(userId, userData, {new: true}).exec();
    }

}

module.exports = UserService;
